package com.example.edu.Service.Impl;

import com.example.edu.Dto.*;
import com.example.edu.Entity.EsDocument;
import com.example.edu.Entity.User;
import com.example.edu.Mapper.DocumentMapper;
import com.example.edu.Mapper.UserMapper;
import com.example.edu.Service.PublicService;
import com.example.edu.Utils.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import static com.example.edu.Utils.MyConstants.*;

@Service
public class PublicServiceImpl implements PublicService {
    @Resource
    private UserMapper userMapper;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    private CacheDataBaseUtil cacheDataBaseUtil;
    @Resource
    private EsUtil esUtil;
    @Resource
    private EmbeddingUtil embeddingUtil;
    @Resource
    private DocumentMapper documentMapper;
    private static final ExecutorService executorService = Executors.newFixedThreadPool(9);
    private static final Logger logger = LoggerFactory.getLogger(PublicServiceImpl.class);

    @Override
    public Return login(LoginDtoG loginData) {
        String telephone = loginData.getTelephone();
        String password = loginData.getPassword();
        // 检查手机号
        if(RegexUtils.isPhoneInvalid(telephone)){
            return Return.fail(2,"无效的手机号");
        }
        User user = cacheDataBaseUtil.selectById(USER_KEY,telephone,User.class, telephone2 -> userMapper.getUser(telephone2),USER_CACHE_TTL, TimeUnit.HOURS);
        if(user == null){
            return Return.fail(3,"未注册的用户");
        }
        if(!password.equals(user.getPassword())){
            return Return.fail(1,"密码错误");
        }
        // 生成token
        String token = JwtUtil.generateToken(telephone);
        // 将token和用户绑定，防止重复登录
        stringRedisTemplate.opsForValue().set(TOKEN_KEY+telephone,token,TOKEN_CACHE_TTL,TimeUnit.HOURS);
        // 获取角色
        int role = user.getRole();
        LoginDtoR loginReturn = new LoginDtoR(role,token);
        return Return.ok(loginReturn);
    }

    @Override
    @Transactional
    public Return register(RegisterDtoG registerData) {
        String telephone = registerData.getTelephone();
        // 检查手机号
        if(RegexUtils.isPhoneInvalid(telephone)){
            return Return.fail(2,"无效的手机号");
        }
        try {
            return register1(telephone,registerData);
        } catch (Exception e){
            return Return.fail(1,"注册失败");
        }
    }

    @Override
    public Return init() {
        try {
            logger.info("======init start======");
            long num_txt = countTxtFiles(INIT_ADDRESS);
            CountDownLatch latch = new CountDownLatch((int) num_txt);
            for(long i = 0;i < num_txt; i++){
                long finalI = i;
                executorService.submit(() -> {
                    try {
                        String content = readFile(INIT_ADDRESS + "/" + finalI + ".txt");
                        List<String> slices = RegexUtils.splitByParagraphs(content);
                        List<List<Double>> embeddings = embeddingUtil.getEmbeddings(slices);
                        List<EsDocument> esDocuments = new ArrayList<>();
                        for(int index = 0; index < slices.size();index++)
                            esDocuments.add(new EsDocument(0,index,finalI+".txt",-1,-1,
                                    0,0,slices.get(index),embeddings.get(index)));
                        esUtil.insertDocuments(esDocuments);
                        latch.countDown();
                    } catch (Exception e) {
                        logger.error("error when init " + finalI + ".txt, the error is : " + e.getMessage());
                    }
                });
            }
            latch.await();
            logger.info("======init success======");
            return Return.ok();
        } catch (Exception e){
            logger.error(e.getMessage());
            return Return.fail(1,"error");
        }
    }

    @Override
    public Return test() {
        return Return.ok();
    }

    @Transactional
    public Return register1(String telephone,RegisterDtoG registerData){
        if(!cacheDataBaseUtil.isContainsById(USER_KEY,telephone, telephone2 -> userMapper.getUser(telephone2),USER_CACHE_TTL,TimeUnit.HOURS)){
            try {
                User new_user = new User(telephone, registerData.getPassword(), registerData.getNickname(), registerData.getRole());
                cacheDataBaseUtil.insert(USER_KEY, telephone, new_user, new_user2 -> userMapper.addUser(new_user2), USER_CACHE_TTL, TimeUnit.HOURS);
                return Return.ok();
            } catch (Exception e){
                logger.error(e.getMessage());
                throw new RuntimeException(e);
            }
        }
        return Return.fail(3,"请勿重复注册");
    }

    public static String readFile(String path) throws IOException {
        return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8);
    }

    public static long countTxtFiles(String directoryPath) {
        try (Stream<Path> files = Files.list(Paths.get(directoryPath))) {
            return files
                    .filter(Files::isRegularFile)               // 过滤出文件（排除文件夹）
                    .filter(path -> path.toString().endsWith(".txt")) // 只要以 .txt 结尾的文件
                    .count();
        } catch (IOException e) {
            logger.error(e.getMessage());
            return 0;
        }
    }
}
